using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Web.UI;

namespace WebChart
{
    public abstract class Chart
    {
        // Fields
        private ChartPointCollection data;
        internal ChartDataLabels dataLabels;
        private object dataSource;
        private string dataXValueField;
        private string dataYValueField;
        private ChartEngine engine;
        private ChartInterior fill;
        private string legend;
        private ChartLine line;
        internal LineMarker lineMarker;
        private string name;
        internal ChartShadow shadow;
        internal bool showLegend;
        internal bool showLineMarkers;

        // Methods
        protected Chart()
            : this(new ChartPointCollection())
        {
        }

        protected Chart(ChartPointCollection data)
            : this(data, Color.Black)
        {
        }

        protected Chart(ChartPointCollection data, Color lineColor)
        {
            this.name = "";
            this.line = new ChartLine();
            this.engine = null;
            this.legend = "";
            this.dataXValueField = "";
            this.dataYValueField = "";
            this.showLegend = true;
            this.lineMarker = LineMarker.Factory.SquareLineMarker;
            this.showLineMarkers = true;
            this.data = data;
            this.Line.Color = lineColor;
            this.fill = new ChartInterior();
            this.dataLabels = new ChartDataLabels();
        }

        public void DataBind()
        {
            if (this.dataSource != null)
            {
                if (!(this.dataSource is IEnumerable))
                {
                    throw new ApplicationException("Data Source has not been established");
                }
                IEnumerator enumerator = ((IEnumerable)this.dataSource).GetEnumerator();
                if (this.data == null)
                {
                    this.data = new ChartPointCollection();
                }
                else
                {
                    this.data.Clear();
                }
                if ((this.dataXValueField == null) || (this.dataXValueField.Length == 0))
                {
                    throw new ArgumentNullException("DataXValueField", "The property DataXValueField needs to be set before calling DataBind");
                }
                if ((this.dataYValueField == null) || (this.dataYValueField.Length == 0))
                {
                    throw new ArgumentNullException("DataYValueField", "The property DataYValueField needs to be set before calling DataBind");
                }
                while (enumerator.MoveNext())
                {
                    string xvalue;
                    float yvalue;
                    object container = enumerator.Current;
                    object propertyValue = null;
                    try
                    {
                        propertyValue = DataBinder.GetPropertyValue(container, this.dataXValueField);
                        xvalue = propertyValue as string;
                        if ((xvalue == null) && (propertyValue != null))
                        {
                            xvalue = propertyValue.ToString();
                        }
                    }
                    catch (InvalidCastException exception)
                    {
                        throw new InvalidCastException(string.Format("Couldn't convert x-value. to a string from {0}", propertyValue), exception);
                    }
                    try
                    {
                        propertyValue = DataBinder.GetPropertyValue(container, this.dataYValueField);
                        if (propertyValue is DBNull)
                        {
                            yvalue = 0f;
                        }
                        else
                        {
                            yvalue = Convert.ToSingle(propertyValue, CultureInfo.InvariantCulture);
                        }
                    }
                    catch (InvalidCastException exception2)
                    {
                        if (propertyValue == null)
                        {
                            throw new InvalidCastException("Unable to read y-value", exception2);
                        }
                        throw new InvalidCastException("Unable to convert y-value, from " + container.GetType().ToString() + " to single", exception2);
                    }
                    this.Data.Add(new ChartPoint(xvalue, yvalue));
                }
            }
        }

        protected virtual void DrawDataLabel(Graphics graphics, string text, RectangleF rectangle, Pen pen, Brush backgroundBrush, StringFormat format, Brush textBrush)
        {
            graphics.FillRectangle(backgroundBrush, rectangle);
            graphics.DrawRectangle(pen, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
            graphics.DrawString(text, this.dataLabels.font, textBrush, rectangle, format);
        }

        protected virtual RectangleF GetDataLabelRectangle(Graphics graphics, float value, string text, int maxWidth, int pointIndex)
        {
            SizeF ef = graphics.MeasureString(text, this.dataLabels.font, maxWidth);
            float x = ((pointIndex + 0.5f) * this.engine.scaleX) - (ef.Width / 2f);
            float y = value * this.engine.scaleY;
            if (this.dataLabels.position == DataLabelPosition.Top)
            {
                y -= ef.Height;
            }
            else if (this.dataLabels.Position == DataLabelPosition.Center)
            {
                y -= ef.Height / 2f;
            }
            return new RectangleF(x, y, ef.Width + 1f, ef.Height);
        }

        protected virtual string GetDataLabelText(ChartPoint point)
        {
            string text = " ";
            if (this.dataLabels.showLegend)
            {
                text = text + this.legend + this.dataLabels.separator;
            }
            if (this.dataLabels.showXTitle)
            {
                text = text + point.xvalue + this.dataLabels.separator;
            }
            if (this.dataLabels.showValue)
            {
                text = text + point.yvalue.ToString(this.dataLabels.numberFormat, CultureInfo.InvariantCulture);
            }
            return text;
        }

        public virtual void GetMinMaxMeanValue(out float min, out float max, out float mean)
        {
            this.data.GetMinMaxMeanValue(out min, out max, out mean);
            if (this.dataLabels.visible)
            {
                float num = (max - min) / 10f;
                max += num;
            }
        }

        public virtual void GetMinMaxXValue(out int min, out int max)
        {
            min = 0;
            if (this.Data != null)
            {
                max = this.Data.Count;
            }
            else
            {
                max = 0;
            }
        }

        public virtual void Render(Graphics graphics, int width, int height)
        {
            ChartEngine engine = this.Engine;
            float scaleX = engine.scaleX;
            float scaleY = engine.scaleY;
            Pen pen = this.Line.GetPen(graphics);
            Point[] pointArray = new Point[this.Data.Count];
            int num3 = 1;
            foreach (ChartPoint point in this.Data)
            {
                if (this.showLineMarkers)
                {
                    this.lineMarker.Render(graphics, (int)((num3 * scaleX) - (scaleX / 2f)), (int)(point.yvalue * scaleY));
                }
                pointArray[num3 - 1] = new Point((int)((num3 * scaleX) - (scaleX / 2f)), (int)(point.yvalue * scaleY));
                if (num3 > 1)
                {
                    graphics.DrawLine(pen, pointArray[num3 - 2], pointArray[num3 - 1]);
                }
                num3++;
            }
            if (this.dataLabels.visible)
            {
                this.RenderDataLabels(graphics);
            }
        }

        protected virtual void RenderDataLabels(Graphics graphics)
        {
            if (this.dataLabels.font == null)
            {
                this.dataLabels.font = ChartText.DefaultFont;
            }
            int maxWidth = this.DataLabelMaxWidth;
            int pointIndex = 0;
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Near;
            Brush backgroundBrush = this.dataLabels.background.GetBrush(graphics);
            Pen pen = this.dataLabels.border.GetPen(graphics);
            Brush textBrush = new SolidBrush(this.dataLabels.foreColor);
            foreach (ChartPoint point in this.data)
            {
                string dataLabelText = this.GetDataLabelText(point);
                RectangleF rectangle = this.GetDataLabelRectangle(graphics, point.yvalue, dataLabelText, maxWidth, pointIndex);
                pointIndex++;
                if ((point.yvalue != 0f) || this.dataLabels.showZeroValues)
                {
                    this.DrawDataLabel(graphics, dataLabelText, rectangle, pen, backgroundBrush, format, textBrush);
                }
            }
            textBrush.Dispose();
            pen.Dispose();
            backgroundBrush.Dispose();
        }

        // Properties
        [Category("Appearance"), PersistenceMode(PersistenceMode.InnerProperty), NotifyParentProperty(true), DefaultValue((string)null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Bindable(true)]
        public ChartPointCollection Data
        {
            get
            {
                return this.data;
            }
        }

        protected virtual int DataLabelMaxWidth
        {
            get
            {
                if (this.dataLabels.maxPointsWidth <= 0)
                {
                    return this.engine.Size.Width;
                }
                return (int)(this.engine.scaleX * this.dataLabels.maxPointsWidth);
            }
        }

        [Bindable(true), NotifyParentProperty(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty), Category("Appearance")]
        public ChartDataLabels DataLabels
        {
            get
            {
                if (this.dataLabels == null)
                {
                    this.dataLabels = new ChartDataLabels();
                }
                return this.dataLabels;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), NotifyParentProperty(true), Browsable(false)]
        public object DataSource
        {
            get
            {
                return this.dataSource;
            }
            set
            {
                if ((value != null) && !(value is IEnumerable))
                {
                    throw new ArgumentException("Invalid data source type");
                }
                this.dataSource = value;
            }
        }

        [DefaultValue(""), NotifyParentProperty(true)]
        public string DataXValueField
        {
            get
            {
                return this.dataXValueField;
            }
            set
            {
                this.dataXValueField = value;
            }
        }

        [DefaultValue(""), NotifyParentProperty(true)]
        public string DataYValueField
        {
            get
            {
                return this.dataYValueField;
            }
            set
            {
                this.dataYValueField = value;
            }
        }

        [NotifyParentProperty(true), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ChartEngine Engine
        {
            get
            {
                return this.engine;
            }
            set
            {
                this.engine = value;
            }
        }

        [PersistenceMode(PersistenceMode.InnerProperty), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), DefaultValue((string)null), Bindable(true), NotifyParentProperty(true), Category("Appearance")]
        public ChartInterior Fill
        {
            get
            {
                return this.fill;
            }
            set
            {
                this.fill = value;
            }
        }

        [NotifyParentProperty(true), DefaultValue("")]
        public string Legend
        {
            get
            {
                return this.legend;
            }
            set
            {
                this.legend = value;
            }
        }

        [NotifyParentProperty(true), Category("Appearance"), DefaultValue((string)null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty), Bindable(true)]
        public ChartLine Line
        {
            get
            {
                return this.line;
            }
        }

        [Browsable(false), NotifyParentProperty(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public LineMarker LineMarker
        {
            get
            {
                return this.lineMarker;
            }
            set
            {
                this.lineMarker = value;
            }
        }

        [Browsable(true), NotifyParentProperty(true), DefaultValue("")]
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }

        [Bindable(true), PersistenceMode(PersistenceMode.InnerProperty), Category("Appearance"), NotifyParentProperty(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartShadow Shadow
        {
            get
            {
                if (this.shadow == null)
                {
                    this.shadow = new ChartShadow();
                }
                return this.shadow;
            }
        }

        [NotifyParentProperty(true), DefaultValue(true)]
        public bool ShowLegend
        {
            get
            {
                return this.showLegend;
            }
            set
            {
                this.showLegend = value;
            }
        }

        [DefaultValue(true), NotifyParentProperty(true)]
        public bool ShowLineMarkers
        {
            get
            {
                return this.showLineMarkers;
            }
            set
            {
                this.showLineMarkers = value;
            }
        }
    }
}
